home *** CD-ROM | disk | FTP | other *** search
- *
- * $VER: exp.s 34.1 (19.1.97)
- *
- * calculates the result of e to the power of x.
- *
- * Version history:
- *
- * 33.1 19.1.97 laukkanen
- *
- * - created (using MacLaurin series approximation with five iterations)
- *
- * 34.1 19.1.97 (c) Motorola
- *
- * - unfortunately the result was only close to the current in the immediate
- * - positive vicinity of zero, scrapped.
- * - cut'n pasted from Motorola M68060SP
- *
- * 34.2 22.1.97 laukkanen
- *
- * - trashed a6, fixed
- *
- * 34.3 23.1.97 (c) Motorola
- *
- * - added expm1()
- *
- * 34.4 24.1.97 laukkanen
- *
- * - in the converting process, I seem to have broken
- * expm1(), fixed.
- *
- * 34.4 24.1.97 laukkanen
- *
- * - exmp1() fixed again.
- *
-
- machine 68040
- fpu 1
-
- XDEF _exp
- XDEF @exp
- XDEF _expm1
- XDEF @expm1
-
- * ALGORITHM and IMPLEMENTATION **************************************** *
- * *
- * exp() *
- * ----- *
- * *
- * Step 1. Filter out extreme cases of input argument. *
- * 1.1 If |X| >= 2^(-65), go to Step 1.3. *
- * 1.2 Go to Step 7. *
- * 1.3 If |X| < 16380 log(2), go to Step 2. *
- * 1.4 Go to Step 8. *
- * Notes: The usual case should take the branches 1.1 -> 1.3 -> 2.*
- * To avoid the use of floating-point comparisons, a *
- * compact representation of |X| is used. This format is a *
- * 32-bit integer, the upper (more significant) 16 bits *
- * are the sign and biased exponent field of |X|; the *
- * lower 16 bits are the 16 most significant fraction *
- * (including the explicit bit) bits of |X|. Consequently, *
- * the comparisons in Steps 1.1 and 1.3 can be performed *
- * by integer comparison. Note also that the constant *
- * 16380 log(2) used in Step 1.3 is also in the compact *
- * form. Thus taking the branch to Step 2 guarantees *
- * |X| < 16380 log(2). There is no harm to have a small *
- * number of cases where |X| is less than, but close to, *
- * 16380 log(2) and the branch to Step 9 is taken. *
- * *
- * Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). *
- * 2.1 Set AdjFlag := 0 (indicates the branch 1.3 -> 2 *
- * was taken) *
- * 2.2 N := round-to-nearest-integer( X * 64/log2 ). *
- * 2.3 Calculate J = N mod 64; so J = 0,1,2,..., *
- * or 63. *
- * 2.4 Calculate M = (N - J)/64; so N = 64M + J. *
- * 2.5 Calculate the address of the stored value of *
- * 2^(J/64). *
- * 2.6 Create the value Scale = 2^M. *
- * Notes: The calculation in 2.2 is really performed by *
- * Z := X * constant *
- * N := round-to-nearest-integer(Z) *
- * where *
- * constant := single-precision( 64/log 2 ). *
- * *
- * Using a single-precision constant avoids memory *
- * access. Another effect of using a single-precision *
- * "constant" is that the calculated value Z is *
- * *
- * Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24). *
- * *
- * This error has to be considered later in Steps 3 and 4. *
- * *
- * Step 3. Calculate X - N*log2/64. *
- * 3.1 R := X + N*L1, *
- * where L1 := single-precision(-log2/64). *
- * 3.2 R := R + N*L2, *
- * L2 := extended-precision(-log2/64 - L1).*
- * Notes: a) The way L1 and L2 are chosen ensures L1+L2 *
- * approximate the value -log2/64 to 88 bits of accuracy. *
- * b) N*L1 is exact because N is no dc.ler than 22 bits *
- * and L1 is no dc.ler than 24 bits. *
- * c) The calculation X+N*L1 is also exact due to *
- * cancellation. Thus, R is practically X+N(L1+L2) to full *
- * 64 bits. *
- * d) It is important to estimate how large can |R| be *
- * after Step 3.2. *
- * *
- * N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24) *
- * X*64/log2 (1+eps) = N + f, |f| <= 0.5 *
- * X*64/log2 - N = f - eps*X 64/log2 *
- * X - N*log2/64 = f*log2/64 - eps*X *
- * *
- * *
- * Now |X| <= 16446 log2, thus *
- * *
- * |X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64 *
- * <= 0.57 log2/64. *
- * This bound will be used in Step 4. *
- * *
- * Step 4. Approximate exp(R)-1 by a polynomial *
- * p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) *
- * Notes: a) In order to reduce memory access, the coefficients *
- * are made as "short" as possible: A1 (which is 1/2), A4 *
- * and A5 are single precision; A2 and A3 are double *
- * precision. *
- * b) Even with the restrictions above, *
- * |p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062. *
- * Note that 0.0062 is slightly bigger than 0.57 log2/64. *
- * c) To fully utilize the pipeline, p is separated into *
- * two independent pieces of roughly equal complexities *
- * p = [ R + R*S*(A2 + S*A4) ] + *
- * [ S*(A1 + S*(A3 + S*A5)) ] *
- * where S = R*R. *
- * *
- * Step 5. Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by *
- * ans := T + ( T*p + t) *
- * where T and t are the stored values for 2^(J/64). *
- * Notes: 2^(J/64) is stored as T and t where T+t approximates *
- * 2^(J/64) to roughly 85 bits; T is in extended precision *
- * and t is in single precision. Note also that T is *
- * rounded to 62 bits so that the last two bits of T are *
- * zero. The reason for such a special form is that T-1, *
- * T-2, and T-8 will all be exact --- a property that will *
- * give much more accurate computation of the function *
- * EXPM1. *
- * *
- * Step 6. Reconstruction of exp(X) *
- * exp(X) = 2^M * 2^(J/64) * exp(R). *
- * 6.1 If AdjFlag = 0, go to 6.3 *
- * 6.2 ans := ans * AdjScale *
- * 6.3 Restore the user FPCR *
- * 6.4 Return ans := ans * Scale. Exit. *
- * Notes: If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R, *
- * |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will *
- * neither overflow nor underflow. If AdjFlag = 1, that *
- * means that *
- * X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380. *
- * Hence, exp(X) may overflow or underflow or neither. *
- * When that is the case, AdjScale = 2^(M1) where M1 is *
- * approximately M. Thus 6.2 will never cause *
- * over/underflow. Possible exception in 6.4 is overflow *
- * or underflow. The inexact exception is not generated in *
- * 6.4. Although one can argue that the inexact flag *
- * should always be raised, to simulate that exception *
- * cost to much than the flag is worth in practical uses. *
- * *
- * Step 7. Return 1 + X. *
- * 7.1 ans := X *
- * 7.2 Restore user FPCR. *
- * 7.3 Return ans := 1 + ans. Exit *
- * Notes: For non-zero X, the inexact exception will always be *
- * raised by 7.3. That is the only exception raised by 7.3.*
- * Note also that we use the FMOVEM instruction to move X *
- * in Step 7.1 to avoid unnecessary trapping. (Although *
- * the FMOVEM may not seem relevant since X is normalized, *
- * the precaution will be useful in the library version of *
- * this code where the separate entry for denormalized *
- * inputs will be done away with.) *
- * *
- * Step 8. Handle exp(X) where |X| >= 16380log2. *
- * 8.1 If |X| > 16480 log2, go to Step 9. *
- * (mimic 2.2 - 2.6) *
- * 8.2 N := round-to-integer( X * 64/log2 ) *
- * 8.3 Calculate J = N mod 64, J = 0,1,...,63 *
- * 8.4 K := (N-J)/64, M1 := truncate(K/2), M = K-M1, *
- * AdjFlag := 1. *
- * 8.5 Calculate the address of the stored value *
- * 2^(J/64). *
- * 8.6 Create the values Scale = 2^M, AdjScale = 2^M1. *
- * 8.7 Go to Step 3. *
- * Notes: Refer to notes for 2.2 - 2.6. *
- * *
- * Step 9. Handle exp(X), |X| > 16480 log2. *
- * 9.1 If X < 0, go to 9.3 *
- * 9.2 ans := Huge, go to 9.4 *
- * 9.3 ans := Tiny. *
- * 9.4 Restore user FPCR. *
- * 9.5 Return ans := ans * ans. Exit. *
- * Notes: Exp(X) will surely overflow or underflow, depending on *
- * X's sign. "Huge" and "Tiny" are respectively large/tiny *
- * extended-precision numbers whose square over/underflow *
- * with an inexact result. Thus, 9.5 always raises the *
- * inexact together with either overflow or underflow. *
- *************************************************************************
-
- cnop 0,4
-
- L2 dc.l $3FDC0000,$82E30865,$4361C4C6,$00000000
-
- EEXPA3 dc.l $3FA55555,$55554CC1
- EEXPA2 dc.l $3FC55555,$55554A54
-
- EM1A4 dc.l $3F811111,$11174385
- EM1A3 dc.l $3FA55555,$55554F5A
-
- EM1A2 dc.l $3FC55555,$55555555,$00000000,$00000000
-
- EM1B8 dc.l $3EC71DE3,$A5774682
- EM1B7 dc.l $3EFA01A0,$19D7CB68
-
- EM1B6 dc.l $3F2A01A0,$1A019DF3
- EM1B5 dc.l $3F56C16C,$16C170E2
-
- EM1B4 dc.l $3F811111,$11111111
- EM1B3 dc.l $3FA55555,$55555555
-
- EM1B2 dc.l $3FFC0000,$AAAAAAAA,$AAAAAAAB
- dc.l $00000000
-
- TWO140 dc.l $48B00000,$00000000
- TWON140
- dc.l $37300000,$00000000
-
- EEXPTBL
- dc.l $3FFF0000,$80000000,$00000000,$00000000
- dc.l $3FFF0000,$8164D1F3,$BC030774,$9F841A9B
- dc.l $3FFF0000,$82CD8698,$AC2BA1D8,$9FC1D5B9
- dc.l $3FFF0000,$843A28C3,$ACDE4048,$A0728369
- dc.l $3FFF0000,$85AAC367,$CC487B14,$1FC5C95C
- dc.l $3FFF0000,$871F6196,$9E8D1010,$1EE85C9F
- dc.l $3FFF0000,$88980E80,$92DA8528,$9FA20729
- dc.l $3FFF0000,$8A14D575,$496EFD9C,$A07BF9AF
- dc.l $3FFF0000,$8B95C1E3,$EA8BD6E8,$A0020DCF
- dc.l $3FFF0000,$8D1ADF5B,$7E5BA9E4,$205A63DA
- dc.l $3FFF0000,$8EA4398B,$45CD53C0,$1EB70051
- dc.l $3FFF0000,$9031DC43,$1466B1DC,$1F6EB029
- dc.l $3FFF0000,$91C3D373,$AB11C338,$A0781494
- dc.l $3FFF0000,$935A2B2F,$13E6E92C,$9EB319B0
- dc.l $3FFF0000,$94F4EFA8,$FEF70960,$2017457D
- dc.l $3FFF0000,$96942D37,$20185A00,$1F11D537
- dc.l $3FFF0000,$9837F051,$8DB8A970,$9FB952DD
- dc.l $3FFF0000,$99E04593,$20B7FA64,$1FE43087
- dc.l $3FFF0000,$9B8D39B9,$D54E5538,$1FA2A818
- dc.l $3FFF0000,$9D3ED9A7,$2CFFB750,$1FDE494D
- dc.l $3FFF0000,$9EF53260,$91A111AC,$20504890
- dc.l $3FFF0000,$A0B0510F,$B9714FC4,$A073691C
- dc.l $3FFF0000,$A2704303,$0C496818,$1F9B7A05
- dc.l $3FFF0000,$A43515AE,$09E680A0,$A0797126
- dc.l $3FFF0000,$A5FED6A9,$B15138EC,$A071A140
- dc.l $3FFF0000,$A7CD93B4,$E9653568,$204F62DA
- dc.l $3FFF0000,$A9A15AB4,$EA7C0EF8,$1F283C4A
- dc.l $3FFF0000,$AB7A39B5,$A93ED338,$9F9A7FDC
- dc.l $3FFF0000,$AD583EEA,$42A14AC8,$A05B3FAC
- dc.l $3FFF0000,$AF3B78AD,$690A4374,$1FDF2610
- dc.l $3FFF0000,$B123F581,$D2AC2590,$9F705F90
- dc.l $3FFF0000,$B311C412,$A9112488,$201F678A
- dc.l $3FFF0000,$B504F333,$F9DE6484,$1F32FB13
- dc.l $3FFF0000,$B6FD91E3,$28D17790,$20038B30
- dc.l $3FFF0000,$B8FBAF47,$62FB9EE8,$200DC3CC
- dc.l $3FFF0000,$BAFF5AB2,$133E45FC,$9F8B2AE6
- dc.l $3FFF0000,$BD08A39F,$580C36C0,$A02BBF70
- dc.l $3FFF0000,$BF1799B6,$7A731084,$A00BF518
- dc.l $3FFF0000,$C12C4CCA,$66709458,$A041DD41
- dc.l $3FFF0000,$C346CCDA,$24976408,$9FDF137B
- dc.l $3FFF0000,$C5672A11,$5506DADC,$201F1568
- dc.l $3FFF0000,$C78D74C8,$ABB9B15C,$1FC13A2E
- dc.l $3FFF0000,$C9B9BD86,$6E2F27A4,$A03F8F03
- dc.l $3FFF0000,$CBEC14FE,$F2727C5C,$1FF4907D
- dc.l $3FFF0000,$CE248C15,$1F8480E4,$9E6E53E4
- dc.l $3FFF0000,$D06333DA,$EF2B2594,$1FD6D45C
- dc.l $3FFF0000,$D2A81D91,$F12AE45C,$A076EDB9
- dc.l $3FFF0000,$D4F35AAB,$CFEDFA20,$9FA6DE21
- dc.l $3FFF0000,$D744FCCA,$D69D6AF4,$1EE69A2F
- dc.l $3FFF0000,$D99D15C2,$78AFD7B4,$207F439F
- dc.l $3FFF0000,$DBFBB797,$DAF23754,$201EC207
- dc.l $3FFF0000,$DE60F482,$5E0E9124,$9E8BE175
- dc.l $3FFF0000,$E0CCDEEC,$2A94E110,$20032C4B
- dc.l $3FFF0000,$E33F8972,$BE8A5A50,$2004DFF5
- dc.l $3FFF0000,$E5B906E7,$7C8348A8,$1E72F47A
- dc.l $3FFF0000,$E8396A50,$3C4BDC68,$1F722F22
- dc.l $3FFF0000,$EAC0C6E7,$DD243930,$A017E945
- dc.l $3FFF0000,$ED4F301E,$D9942B84,$1F401A5B
- dc.l $3FFF0000,$EFE4B99B,$DCDAF5CC,$9FB9A9E3
- dc.l $3FFF0000,$F281773C,$59FFB138,$20744C05
- dc.l $3FFF0000,$F5257D15,$2486CC2C,$1F773A19
- dc.l $3FFF0000,$F7D0DF73,$0AD13BB8,$1FFE90D5
- dc.l $3FFF0000,$FA83B2DB,$722A033C,$A041ED22
- dc.l $3FFF0000,$FD3E0C0C,$F486C174,$1F853F3A
-
-
- SCALE EQU -16
- ADJSCALE EQU -28
- SC EQU -16
- ONEBYSC EQU -28
- L_SCR1 EQU -4
- TEMP_SIZE EQU 28
-
-
- _exp
- fmove.d (4,sp),fp0
- @exp
-
- ;--Step 2.
- ;--This is the normal branch: 2^(-65) <= |X| < 16380 log2.
- fmove.s fp0,-(sp)
- move.w (sp),d0
- addq.l #4,sp
- and.w #$7f80,d0
- beq .zero
-
- fmove.x fp0,fp1
- fmul.s #$42B8AA3B,fp0 ; 64/log2 * X
- link a0,#-TEMP_SIZE
- fmovem.x fp2/fp3,-(sp) ; save fp2 {fp2/fp3}
- fmove.l fp0,d1 ; N = int( X * 64/log2 )
- lea (EEXPTBL,pc),a1
- fmove.l d1,fp0 ; convert to floating-format
-
- move.l d1,d0 ; save N temporarily
- and.l #$3F,d1 ; D0 is J = N mod 64
- asr.l #6,d0 ; D0 is M
- fmove.x fp0,fp2
- lsl.l #4,d1
- fmul.s #$BC317218,fp0 ; N * L1, L1 = lead(-log2/64)
- add.w #$3FFF,d0 ; biased expo. of 2^(M)
- add.l d1,a1 ; address of 2^(J/64)
- move.w (L2,pc),(L_SCR1,a0) ; prefetch L2, no need in CB
-
- .EXPCONT1
- ;--Step 3.
- ;--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
- ;--a0 points to 2^(J/64), D0 is biased expo. of 2^(M)
- fmul.x (L2,pc),fp2 ; N * L2, L1+L2 = -log2/64
- fadd.x fp1,fp0 ; X + N*L1
- fadd.x fp2,fp0 ; fp0 is R, reduced arg.
-
- ;--Step 4.
- ;--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
- ;-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))
- ;--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
- ;--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))]
-
- fmove.x fp0,fp1
- fmul.x fp1,fp1 ; fp1 IS S = R*R
-
- fmove.s #$3AB60B70,fp2 ; fp2 IS A5
-
- fmul.x fp1,fp2 ; fp2 IS S*A5
- fmove.x fp1,fp3
- fmul.s #$3C088895,fp3 ; fp3 IS S*A4
-
- fadd.d (EEXPA3,pc),fp2 ; fp2 IS A3+S*A5
- fadd.d (EEXPA2,pc),fp3 ; fp3 IS A2+S*A4
-
- fmul.x fp1,fp2 ; fp2 IS S*(A3+S*A5)
- move.w d0,(SCALE,a0) ; SCALE is 2^(M) in extended
- move.l #$80000000,(SCALE+4,a0)
- clr.l (SCALE+8,a0)
-
- fmul.x fp1,fp3 ; fp3 IS S*(A2+S*A4)
-
- fadd.s #$3F000000,fp2 ; fp2 IS A1+S*(A3+S*A5)
- fmul.x fp0,fp3 ; fp3 IS R*S*(A2+S*A4)
-
- fmul.x fp1,fp2 ; fp2 IS S*(A1+S*(A3+S*A5))
- fadd.x fp3,fp0 ; fp0 IS R+R*S*(A2+S*A4),
-
- fmove.x (a1)+,fp1 ; fp1 is lead. pt. of 2^(J/64)
- fadd.x fp2,fp0 ; fp0 is EXP(R) - 1
-
- ;--Step 5
- ;--final reconstruction process
- ;--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) )
-
- fmul.x fp1,fp0 ; 2^(J/64)*(Exp(R)-1)
- fmovem.x (sp)+,fp2/fp3 ; fp2 restored {fp2/fp3}
- fadd.s (a1),fp0 ; accurate 2^(J/64)
-
- fadd.x fp1,fp0 ; 2^(J/64) + 2^(J/64)*...
-
- .NORMAL
- fmul.x (SCALE,a0),fp0 ; multiply 2^(M)
- unlk a0
- rts
- .zero
- fmove.s #1,fp0
- rts
-
- *************************************************************************
- * expm1(): computes the exponential minus 1 for a normalized input *
- * *
- * INPUT *************************************************************** *
- * fp0 = extended precision input *
- * *
- * OUTPUT ************************************************************** *
- * fp0 = exp(X) or exp(X)-1 *
- * *
- * ACCURACY and MONOTONICITY ******************************************* *
- * The returned result is within 0.85 ulps in 64 significant bit, *
- * i.e. within 0.5001 ulp to 53 bits if the result is subsequently *
- * rounded to double precision. The result is provably monotonic *
- * in double precision. *
- * *
- * ALGORITHM and IMPLEMENTATION **************************************** *
- * *
- * Step 1. Check |X| *
- * 1.1 If |X| >= 1/4, go to Step 1.3. *
- * 1.2 Go to Step 7. *
- * 1.3 If |X| < 70 log(2), go to Step 2. *
- * 1.4 Go to Step 10. *
- * Notes: The usual case should take the branches 1.1 -> 1.3 -> 2.*
- * However, it is conceivable |X| can be small very often *
- * because EXPM1 is intended to evaluate exp(X)-1 *
- * accurately when |X| is small. For further details on *
- * the comparisons, see the notes on Step 1 of setox. *
- * *
- * Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). *
- * 2.1 N := round-to-nearest-integer( X * 64/log2 ). *
- * 2.2 Calculate J = N mod 64; so J = 0,1,2,..., *
- * or 63. *
- * 2.3 Calculate M = (N - J)/64; so N = 64M + J. *
- * 2.4 Calculate the address of the stored value of *
- * 2^(J/64). *
- * 2.5 Create the values Sc = 2^M and *
- * OnebySc := -2^(-M). *
- * Notes: See the notes on Step 2 of setox. *
- * *
- * Step 3. Calculate X - N*log2/64. *
- * 3.1 R := X + N*L1, *
- * where L1 := single-precision(-log2/64). *
- * 3.2 R := R + N*L2, *
- * L2 := extended-precision(-log2/64 - L1).*
- * Notes: Applying the analysis of Step 3 of setox in this case *
- * shows that |R| <= 0.0055 (note that |X| <= 70 log2 in *
- * this case). *
- * *
- * Step 4. Approximate exp(R)-1 by a polynomial *
- * p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6))))) *
- * Notes: a) In order to reduce memory access, the coefficients *
- * are made as "short" as possible: A1 (which is 1/2), A5 *
- * and A6 are single precision; A2, A3 and A4 are double *
- * precision. *
- * b) Even with the restriction above, *
- * |p - (exp(R)-1)| < |R| * 2^(-72.7) *
- * for all |R| <= 0.0055. *
- * c) To fully utilize the pipeline, p is separated into *
- * two independent pieces of roughly equal complexity *
- * p = [ R*S*(A2 + S*(A4 + S*A6)) ] + *
- * [ R + S*(A1 + S*(A3 + S*A5)) ] *
- * where S = R*R. *
- * *
- * Step 5. Compute 2^(J/64)*p by *
- * p := T*p *
- * where T and t are the stored values for 2^(J/64). *
- * Notes: 2^(J/64) is stored as T and t where T+t approximates *
- * 2^(J/64) to roughly 85 bits; T is in extended precision *
- * and t is in single precision. Note also that T is *
- * rounded to 62 bits so that the last two bits of T are *
- * zero. The reason for such a special form is that T-1, *
- * T-2, and T-8 will all be exact --- a property that will *
- * be exploited in Step 6 below. The total relative error *
- * in p is no bigger than 2^(-67.7) compared to the final *
- * result. *
- * *
- * Step 6. Reconstruction of exp(X)-1 *
- * exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ). *
- * 6.1 If M <= 63, go to Step 6.3. *
- * 6.2 ans := T + (p + (t + OnebySc)). Go to 6.6 *
- * 6.3 If M >= -3, go to 6.5. *
- * 6.4 ans := (T + (p + t)) + OnebySc. Go to 6.6 *
- * 6.5 ans := (T + OnebySc) + (p + t). *
- * 6.6 Restore user FPCR. *
- * 6.7 Return ans := Sc * ans. Exit. *
- * Notes: The various arrangements of the expressions give *
- * accurate evaluations. *
- * *
- * Step 7. exp(X)-1 for |X| < 1/4. *
- * 7.1 If |X| >= 2^(-65), go to Step 9. *
- * 7.2 Go to Step 8. *
- * *
- * Step 8. Calculate exp(X)-1, |X| < 2^(-65). *
- * 8.1 If |X| < 2^(-16312), goto 8.3 *
- * 8.2 Restore FPCR; return ans := X - 2^(-16382). *
- * Exit. *
- * 8.3 X := X * 2^(140). *
- * 8.4 Restore FPCR; ans := ans - 2^(-16382). *
- * Return ans := ans*2^(140). Exit *
- * Notes: The idea is to return "X - tiny" under the user *
- * precision and rounding modes. To avoid unnecessary *
- * inefficiency, we stay away from denormalized numbers *
- * the best we can. For |X| >= 2^(-16312), the *
- * straightforward 8.2 generates the inexact exception as *
- * the case warrants. *
- * *
- * Step 9. Calculate exp(X)-1, |X| < 1/4, by a polynomial *
- * p = X + X*X*(B1 + X*(B2 + ... + X*B12)) *
- * Notes: a) In order to reduce memory access, the coefficients *
- * are made as "short" as possible: B1 (which is 1/2), B9 *
- * to B12 are single precision; B3 to B8 are double *
- * precision; and B2 is double extended. *
- * b) Even with the restriction above, *
- * |p - (exp(X)-1)| < |X| 2^(-70.6) *
- * for all |X| <= 0.251. *
- * Note that 0.251 is slightly bigger than 1/4. *
- * c) To fully preserve accuracy, the polynomial is *
- * computed as *
- * X + ( S*B1 + Q ) where S = X*X and *
- * Q = X*S*(B2 + X*(B3 + ... + X*B12)) *
- * d) To fully utilize the pipeline, Q is separated into *
- * two independent pieces of roughly equal complexity *
- * Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] + *
- * [ S*S*(B3 + S*(B5 + ... + S*B11)) ] *
- * *
- * Step 10. Calculate exp(X)-1 for |X| >= 70 log 2. *
- * 10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all *
- * practical purposes. Therefore, go to Step 1 of setox. *
- * 10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical *
- * purposes. *
- * ans := -1 *
- * Restore user FPCR *
- * Return ans := ans + 2^(-126). Exit. *
- * Notes: 10.2 will always create an inexact and return -1 + tiny *
- * in the user rounding precision and mode. *
- * *
- *************************************************************************
-
- _expm1
- fmove.d (4,sp),fp0
- @expm1
- ;--entry point for EXPM1(X), here X is finite, non-zero, non-NaN
-
- ;--Step 1.
- ;--Step 1.1
- link a0,#-TEMP_SIZE
- fmove.x fp0,(SC,a0)
- move.l (SC,a0),d1 ; load part of input X
- and.l #$7FFF0000,d1 ; biased expo. of X
- cmp.l #$3FFD0000,d1 ; 1/4
- bge.b .EM1CON1 ; |X| >= 1/4
- bra .EM1SM
-
- .EM1CON1
- ;--Step 1.3
- ;--The case |X| >= 1/4
- move.w (SC+4,a0),d1 ; expo. and partial sig. of |X|
- cmp.l #$4004C215,d1 ; 70log2 rounded up to 16 bits
- ble.b .EM1MAIN ; 1/4 <= |X| <= 70log2
- bra .EM1BIG
-
- .EM1MAIN
- ;--Step 2.
- ;--This is the case: 1/4 <= |X| <= 70 log2.
-
- fmove.x fp0,fp1
- fmul.s #$42B8AA3B,fp0 ; 64/log2 * X
- fmovem.x fp2/fp3,-(sp) ; save fp2 {fp2/fp3}
- fmove.l fp0,d1 ; N = int( X * 64/log2 )
- lea (EEXPTBL,pc),a1
- fmove.l d1,fp0 ; convert to floating-format
- move.l d1,(L_SCR1,a0) ; save N temporarily
- and.l #$3F,d1 ; D0 is J = N mod 64
- lsl.l #4,d1
- add.l d1,a1 ; address of 2^(J/64)
- move.l (L_SCR1,a0),d1
- asr.l #6,d1 ; D0 is M
- move.l d1,(L_SCR1,a0) ; save a copy of M
-
- ;--Step 3.
- ;--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
- ;--a0 points to 2^(J/64), D0 and a1 both contain M
- fmove.x fp0,fp2
- fmul.s #$BC317218,fp0 ; N * L1, L1 = lead(-log2/64)
- fmul.x (L2,pc),fp2 ; N * L2, L1+L2 = -log2/64
- fadd.x fp1,fp0 ; X + N*L1
- fadd.x fp2,fp0 ; fp0 is R, reduced arg.
- add.w #$3FFF,d1 ; D0 is biased expo. of 2^M
-
- ;--Step 4.
- ;--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
- ;-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6)))))
- ;--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
- ;--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))]
-
- fmove.x fp0,fp1
- fmul.x fp1,fp1 ; fp1 IS S = R*R
-
- fmove.s #$3950097B,fp2 ; fp2 IS a6
-
- fmul.x fp1,fp2 ; fp2 IS S*A6
- fmove.x fp1,fp3
- fmul.s #$3AB60B6A,fp3 ; fp3 IS S*A5
-
- fadd.d (EM1A4,pc),fp2 ; fp2 IS A4+S*A6
- fadd.d (EM1A3,pc),fp3 ; fp3 IS A3+S*A5
- move.w d1,(SC,a0) ; SC is 2^(M) in extended
- move.l #$80000000,(SC+4,a0)
- clr.l (SC+8,a0)
-
- fmul.x fp1,fp2 ; fp2 IS S*(A4+S*A6)
- move.l (L_SCR1,a0),d1 ; D0 is M
- neg.w d1 ; D0 is -M
- fmul.x fp1,fp3 ; fp3 IS S*(A3+S*A5)
- add.w #$3FFF,d1 ; biased expo. of 2^(-M)
- fadd.d (EM1A2,pc),fp2 ; fp2 IS A2+S*(A4+S*A6)
- fadd.s #$3F000000,fp3 ; fp3 IS A1+S*(A3+S*A5)
- fmul.x fp1,fp2 ; fp2 IS S*(A2+S*(A4+S*A6))
- or.w #$8000,d1 ; signed/expo. of -2^(-M)
- move.w d1,(ONEBYSC,a0) ; OnebySc is -2^(-M)
- move.l #$80000000,(ONEBYSC+4,a0)
- clr.l (ONEBYSC+8,a0)
- fmul.x fp3,fp1 ; fp1 IS S*(A1+S*(A3+S*A5))
-
- fmul.x fp0,fp2 ; fp2 IS R*S*(A2+S*(A4+S*A6))
- fadd.x fp1,fp0 ; fp0 IS R+S*(A1+S*(A3+S*A5))
-
- fadd.x fp2,fp0 ; fp0 IS EXP(R)-1
-
- fmovem.x (sp)+,fp2/fp3 ; fp2 restored {fp2/fp3}
-
- ;--Step 5
- ;--Compute 2^(J/64)*p
-
- fmul.x (a1),fp0 ; 2^(J/64)*(Exp(R)-1)
-
- ;--Step 6
- ;--Step 6.1
- move.l (L_SCR1,a0),d1 ; retrieve M
- cmp.l #63,d1
- ble.b .MLE63
- ;--Step 6.2 M >= 64
- fmove.s (12,a1),fp1 ; fp1 is t
- fadd.x (ONEBYSC,a0),fp1 ; fp1 is t+OnebySc
- fadd.x fp1,fp0 ; p+(t+OnebySc), fp1 released
- fadd.x (a1),fp0 ; T+(p+(t+OnebySc))
- bra .EM1SCALE
- .MLE63:
- ;--Step 6.3 M <= 63
- cmp.l #-3,d1
- bge.b .MGEN3
- .MLTN3:
- ;--Step 6.4 M <= -4
- fadd.s (12,a1),fp0 ; p+t
- fadd.x (a1),fp0 ; T+(p+t)
- fadd.x (ONEBYSC,a0),fp0 ; OnebySc + (T+(p+t))
- bra .EM1SCALE
- .MGEN3
- ;--Step 6.5 -3 <= M <= 63
- fmove.x (a1)+,fp1 ; fp1 is T
- fadd.s (a1),fp0 ; fp0 is p+t
- fadd.x (ONEBYSC,a0),fp1 ; fp1 is T+OnebySc
- fadd.x fp1,fp0 ; (T+OnebySc)+(p+t)
- .EM1SCALE
- ;--Step 6.6
- fmul.x (SC,a0),fp0
- unlk a0
- rts
-
- .EM1SM
- ;--Step 7 |X| < 1/4.
- cmp.l #$3FBE0000,d1 ; 2^(-65)
- bge.b .EM1POLY
-
- .EM1TINY
- ;--Step 8 |X| < 2^(-65)
- cmp.l #$00330000,d1 ; 2^(-16312)
- blt.b .EM12TINY
- ;--Step 8.2
- move.l #$80010000,(SC,a0) ; SC is -2^(-16382)
- move.l #$80000000,(SC+4,a0)
- clr.l (SC+8,a0)
-
- fadd.x (SC,a0),fp0
- unlk a0
- rts
-
- .EM12TINY
- ;--Step 8.3
- fmul.d (TWO140,pc),fp0
- move.l #$80010000,(SC,a0)
- move.l #$80000000,(SC+4,a0)
- clr.l (SC+8,a0)
- fadd.x (SC,a0),fp0
- fmul.d (TWON140,pc),fp0
- unlk a0
- rts
-
- .EM1POLY
- ;--Step 9 exp(X)-1 by a simple polynomial
- fmul.x fp0,fp0 ; fp0 is S := X*X
- fmovem.x fp2/fp3,-(sp) ; save fp2 {fp2/fp3}
- fmove.s #$2F30CAA8,fp1 ; fp1 is B12
- fmul.x fp0,fp1 ; fp1 is S*B12
- fmove.s #$310F8290,fp2 ; fp2 is B11
- fadd.s #$32D73220,fp1 ; fp1 is B10+S*B12
- fmul.x fp0,fp2 ; fp2 is S*B11
- fmul.x fp0,fp1 ; fp1 is S*(B10 + ...
-
- fadd.s #$3493F281,fp2 ; fp2 is B9+S*...
- fadd.d (EM1B8,pc),fp1 ; fp1 is B8+S*...
-
- fmul.x fp0,fp2 ; fp2 is S*(B9+...
- fmul.x fp0,fp1 ; fp1 is S*(B8+...
-
- fadd.d (EM1B7,pc),fp2 ; fp2 is B7+S*...
- fadd.d (EM1B6,pc),fp1 ; fp1 is B6+S*...
-
- fmul.x fp0,fp2 ; fp2 is S*(B7+...
- fmul.x fp0,fp1 ; fp1 is S*(B6+...
-
- fadd.d (EM1B5,pc),fp2 ; fp2 is B5+S*...
- fadd.d (EM1B4,pc),fp1 ; fp1 is B4+S*...
-
- fmul.x fp0,fp2 ; fp2 is S*(B5+...
- fmul.x fp0,fp1 ; fp1 is S*(B4+...
-
- fadd.d (EM1B3,pc),fp2 ; fp2 is B3+S*...
- fadd.x (EM1B2,pc),fp1 ; fp1 is B2+S*...
-
- fmul.x fp0,fp2 ; fp2 is S*(B3+...
- fmul.x fp0,fp1 ; fp1 is S*(B2+...
-
- fmul.x fp0,fp2 ; fp2 is S*S*(B3+...)
- fmul.x (SC,a0),fp1 ; fp1 is X*S*(B2...
-
- fmul.s #$3F000000,fp0 ; fp0 is S*B1
- fadd.x fp2,fp1 ; fp1 is Q
-
- fmovem.x (sp)+,fp2/fp3 ; fp2 restored {fp2/fp3}
-
- fadd.x fp1,fp0 ; fp0 is S*B1+Q
-
- fadd.x (SC,a0),fp0
- unlk a0
- rts
-
- .EM1BIG
- ;--Step 10 |X| > 70 log2
- move.l (SC,a0),d1
- unlk a0
- tst.l d1
- bgt.w @exp
-
- ;--Step 10.2
- fmove.s #$BF800000,fp0 ; fp0 is -1
- fadd.s #$00800000,fp0 ; -1 + 2^(-126)
- unlk a0
- rts
-